#ifndef _SECTORMANAGER_
#define _SECTORMANAGER_

#include "base.h"
#include "aerial\Core\NetMessage.h"
#include "aerial\Core\NetIO.h"

#include <iostream>
#include <map>

#include "PlatformMessage.h"

#include "raknet\Gets.h"
#include "raknet\BitStream.h"
#include "raknet\GetTime.h"
#include "raknet\MessageFilter.h"
#include "raknet\MessageIdentifiers.h"
#include "raknet\RakNetTypes.h"
#include "raknet\StringCompressor.h"
#include "raknet\RakPeerInterface.h"

using namespace std;
using namespace RakNet;
using namespace air;

struct Player
{
	Player(): ready(false), flyObjectType(0), side(0) {}
	Player(uchar fot, uchar _side, int _id, SystemAddress& _sa)
		: flyObjectType(fot), side(_side), ready(false), sa(_sa) {}

	SystemAddress sa;
	bool ready;
	uchar flyObjectType;
	uchar side;
};

typedef map<RakString, Player> mapSector;

struct PlayerSector {
	RakString sectorName;
	Player owner;

	int playerCount;
	bool isPlaying;

	SystemAddress hostAddr;
	map<RakString, Player> playerList;

	void Serialization(BitStream* bso)
	{
		bso->Write(playerCount);
		sectorName.Serialize(bso);
		sectorName.Serialize(bso);
		bso->Write(owner.flyObjectType);
		bso->Write(owner.side);
		const char* str = owner.sa.ToString();
		RakString rak_str(str);
		rak_str.Serialize(bso);
		bso->Write(owner.ready);
		for (map<RakString, Player>::iterator it = playerList.begin(); it != playerList.end(); it++)
		{
			if (it->first != sectorName) {
				it->first.Serialize(bso);
				bso->Write(it->second.flyObjectType);
				bso->Write(it->second.side);
				// serialize ip address
				const char* str = it->second.sa.ToString();
				RakString rak_str(str);
				rak_str.Serialize(bso);
				bso->Write(it->second.ready);	
			}
		}
	}

	PlayerSector(const RakString& ownerId, SystemAddress& addr)
		: sectorName(ownerId), playerCount(0), isPlaying(false)
	{
		owner.sa = addr;
		owner.ready = true;
		playerList.insert(pair<RakString, Player>(ownerId, owner));
		hostAddr = addr;
	}

	map<RakString, Player>& getPlayerList() {
		return playerList;
	}

	void start() {
		//
		isPlaying = true;
	}

	void addPlayer(const RakString& playerId, SystemAddress& addr) {
		Player p;
		playerList.insert(pair<RakString, Player>(
			playerId, Player()
			));
		++playerCount;
	}

	void removePlayer(const RakString& playerId) {
		RakString username = playerId;
		mapSector::iterator it = playerList.find(username);
		if (it != playerList.end()) {
			playerList.erase(it);
			--playerCount;	
		}
	}

	bool readyPlayer(const RakString& playerId) {
		RakString username = playerId;
		mapSector::iterator it = playerList.find(username);
		if (it != playerList.end()) {
			it->second.ready = true;
			return true;
		}
		return false;
	}

	bool cancelPlayer(const RakString& playerId) {
		RakString username = playerId;
		mapSector::iterator it = playerList.find(username);
		if (it != playerList.end()) {
			it->second.ready = false;
			return true;
		}
		return false;
	}
};

class SectorManager {
public:
	SectorManager();
	~SectorManager();

	void ProcessMessage();
	void SendMessage(PlatformMessage*, const SystemAddress&);
	void SectorManager::SendMessage(BitStream* bso, const SystemAddress& addr);
	void BroadcastExcludePlayer(PlatformMessage* msg, const SystemAddress& addr);
	/*void forwardMessage(PlatformMessage*, PlayerSector&, const RakNetGUID& guid);*/

	// player' s action
	void CreateSector(PlatformMessageCreate& msg, SystemAddress& sa);
	void LeaveSector(PlatformMessageJoin& msg, SystemAddress& sa);
	bool JoinSector(PlatformMessageJoin& pmj, SystemAddress& sa);

	bool ReadySector(PlatformMessageJoin& pmj, SystemAddress& sa);
	bool CancelReadySector(PlatformMessageJoin& pmj, SystemAddress& sa);

	void UpdateRoomInfo(BitStream*);
	void ListRoom();
	bool GetRoomInfo(PlatformMessageJoin& pmj, BitStream*);

private:
	map<RakString, PlayerSector> sectorContainer;
	RakNet::RakPeerInterface* serverNode;
	RakNet::Packet* p;

	int roomCount;
};


#endif